#include "global.h"
#include "common.h"
#include "tool.h"
#include "entity.h"
#include "hgegui.h"
#include "scene_manager.h"
#include "logic_manager.h"
#include "physics_manager.h"
#include "hgesprite.h"
#include "hgefont.h"
#include "gui_manager.h"
#include "pass_manager.h"
#include "pugixml\pugixml.hpp"

scene_manager::scene_manager()
: fnt(new hgeFont("media/font1.fnt"))
, quad_transparent(255)
, screen_gfx_speed(600.0f)
, g(new goal_info)
, quad(new hgeQuad)
, first_init(false)
{
	//init bg
	bg = new hgeSprite(hge->Texture_Load("media/bg.jpg"), 0, 0, 800, 600);
	notice = new hgeSprite(hge->Texture_Load("media/notice_1.png"), 0, 0, 300, 100);

	//init gfx quad
	quad->blend = BLEND_ALPHABLEND | BLEND_COLORMUL | BLEND_NOZWRITE;
	for(int i=0;i<4;i++)
	{
		quad->v[i].z=0.5f;
		quad->v[i].col=ARGB(255, 0, 0, 0);
	}
	quad->v[0].x=0; quad->v[0].y=0; 
	quad->v[1].x=800; quad->v[1].y=0; 
	quad->v[2].x=800; quad->v[2].y=600; 
	quad->v[3].x=0; quad->v[3].y=600; 

	//--------------screen bound wall build
	physics_manager::get_instance()->set_screen_bound(cpv(0, -500), cpv(hge->System_GetState(HGE_SCREENWIDTH), hge->System_GetState(HGE_SCREENHEIGHT)));
}

scene_manager::~scene_manager()
{
	clear_scene();
	hge->System_Shutdown();
	hge->Release();
}

void scene_manager::clear_scene()
{
	if (first_init)
	{
		for (size_t i=0; i<entitys.size(); ++i)
		{
			physics_manager::get_instance()->delete_entity_from_space(entitys[i]);
			hge->Texture_Free(entitys[i]->sprite->GetTexture());
			delete entitys[i]->sprite;
		}
		entitys.clear();
		vector<entity*>().swap(entitys);
		hge->Texture_Free(g->sprite->GetTexture());
		delete g->sprite;
	}
}

//read xml file to add entitys to scene
bool scene_manager::load_scene(char* scenefile)
{
	//load xml file
	pugi::xml_document doc;
	doc.load_file(scenefile);
	
	//init goal
	pugi::xml_node goal_node = doc.child("scene").child("goal");
	g->pos = xml_get_attrib_int_pair(goal_node, "pos");
	g->width = xml_get_attrib_int(goal_node, "width");
	g->height = xml_get_attrib_int(goal_node, "height");
	char* tex = xml_get_attrib_pchar(goal_node, "tex");
	g->sprite = new hgeSprite(hge->Texture_Load(tex), 0, 0, g->width, g->height);

	//-------------traverse scene entitys
    pugi::xml_node entitys_node = doc.child("scene").child("entitys");
	//search all entity
	for (pugi::xml_node entity_node = entitys_node.child("entity"); entity_node; entity_node = entity_node.next_sibling())
	{
        entity* e = new entity;
		e->name = (char*)(entity_node.attribute("name").value());

		if (!strcmp(e->name, "goal"))
		{
			goal_entity = e;
		}

		char* texfile = xml_get_attrib_pchar(entity_node, "imagefile");
		float_pair position = xml_get_attrib_float_pair(entity_node, "position");
		float width = xml_get_attrib_float(entity_node, "width");
		float height = xml_get_attrib_float(entity_node, "height");
		float mass = xml_get_attrib_float(entity_node, "mass");
		float radius = xml_get_attrib_float(entity_node, "radius");

		e->sprite = new hgeSprite(hge->Texture_Load(texfile), 0, 0, width, height);
		e->sprite->SetHotSpot(width/2.0f, height/2.0f);

		e->body = physics_manager::get_instance()->make_body(mass, position.x, position.y, radius);

		//search all shapes for the entity(body)
		for (pugi::xml_node shape_node = entity_node.child("shape"); shape_node; shape_node = shape_node.next_sibling())
		{
			int type = xml_get_attrib_int(shape_node, "type");
			float elasticity = xml_get_attrib_float(shape_node, "elasticity");
			float friction = xml_get_attrib_float(shape_node, "friction");
			cpShape* s;

			if (type==1)
			{
				float radius = xml_get_attrib_float(shape_node, "radius");
				s = physics_manager::get_instance()->make_circle_shape(radius, elasticity, friction, e->body);
				e->shapes.push_back(s);
			}

			else if (type==2)
			{
                int vertex_count = xml_get_attrib_int(shape_node, "vcount");
				cpVect* pVect = new cpVect[vertex_count];
				for (int i=0; i<vertex_count; i++)
				{
					//vertex attrib name (v0 ~ v999)
                    char v[4];
					sprintf(v, "v%d", i);
                    float_pair vertex = xml_get_attrib_float_pair(shape_node, v);
					pVect[i] = tool::get_instance()->float_pair_to_cpVect(vertex);
				}
				s = physics_manager::get_instance()->make_poly_shape(vertex_count, pVect, elasticity, friction, e->body);
				e->shapes.push_back(s);
			}
       	}

		physics_manager::get_instance()->add_entity_to_space(e);
	    entitys.push_back(e);
	}
	first_init = true;
	return true;
}

//render function (static)
bool scene_manager::scene_render()
{
	hge->Gfx_BeginScene();

    //----------
	switch(logic_manager::get_instance()->get_current_state()->id)
	{
	    case STATE_GAME_DOING:
		    get_instance()->render_bg();
		    get_instance()->render_entitys();
		    get_instance()->render_fps();
			get_instance()->render_goal();
			if (pass_manager::get_instance()->get_current_scene() == 0)
			{
				get_instance()->notice->Render(350,400);
			}
			get_instance()->render_keep_time();
			gui_manager::get_instance()->get_gui()->Render();
			break;

		case STATE_MAIN_MENU:
			get_instance()->render_bg();
			gui_manager::get_instance()->get_gui()->Render();
			break;

		case STATE_SCENE_SELECT:
			get_instance()->render_bg();
			gui_manager::get_instance()->get_gui()->Render();
			break;

		default:
			break;
	}

	get_instance()->do_screen_fade_inout();
	//----------
	hge->Gfx_EndScene();
	return false;
}

void scene_manager::render_bg()
{
    bg->Render(0, 0);
}

void scene_manager::render_entitys()
{
	for (size_t i=0; i<entitys.size(); i++)
	{
		entity* e = entitys[i];
        e->sprite->RenderEx(e->body->p.x, e->body->p.y, cpBodyGetAngle(e->body), 1, 1);
	}
}

void scene_manager::render_fps()
{
    fnt->printf(5, 5, HGETEXT_LEFT, "FPS:%d (max=100)", hge->Timer_GetFPS());
}

void scene_manager::render_goal()
{
	g->sprite->Render(g->pos.x, g->pos.y);
}

entity* scene_manager::get_goal_entity()
{
    return goal_entity;
}

goal_info* scene_manager::get_goal_info()
{
    return g;
}

void scene_manager::set_screen_fade_inout(int gfx)
{
	if (gfx==SCREEN_FADE_IN)
	{
        quad_transparent = 255;
	}
	else if (gfx==SCREEN_FADE_OUT)
	{
		quad_transparent = 0;
	} 
    screen_gfx_state = gfx;
}

void scene_manager::render_keep_time()
{
	fnt->printf(g->pos.x+g->width+10, g->pos.y, HGETEXT_LEFT, "keep:%fs (>1.2s)", pass_manager::get_instance()->get_keep_time());
}

//screen fade in/out control
void scene_manager::do_screen_fade_inout()
{
    if (screen_gfx_state==SCREEN_NORMAL)
	{
		return;
	}

	if (screen_gfx_state==SCREEN_FADE_IN)
	{
		quad_transparent -= hge->Timer_GetDelta()*screen_gfx_speed;
		if (quad_transparent<=1)
		{
			quad_transparent = 0;
            screen_gfx_state = SCREEN_NORMAL;
		}
		else
		{
			for(int i=0;i<4;i++)
			{
				quad->v[i].col=ARGB((int)(quad_transparent), 0, 0, 0);
			}
		}
	}

	if (screen_gfx_state==SCREEN_FADE_OUT)
	{
		quad_transparent += hge->Timer_GetDelta()*screen_gfx_speed;
		if (quad_transparent>=255)
		{
			quad_transparent = 255;
			screen_gfx_state = SCREEN_NORMAL;
		}
		else
		{
			for(int i=0;i<4;i++)
			{
				quad->v[i].col = ARGB((int)(quad_transparent), 0, 0, 0);
			}
		}
	}

	hge->Gfx_RenderQuad(quad);
}